/*
 * device.c
 *
 *  Created on: 2021年7月25日
 *      Author: Administrator
 */

#include "device.h"

#define DEBUG_TAG "device,%d", __LINE__
#define DEBUG_LEVEL DEBUG_OUTPUT
#include "debug.h"

static list_t device_list = {&device_list, &device_list};

/*
 * 获取设备
 *
 * @param device 设备句柄
 * @param oflag 打开方式
 *
 * @return 成功返回EOK
 */
static int __device_take(device_t *device, uint32_t oflag)
{
    //检查并设置打开方式
    if((device->flags & oflag) != oflag) {
        LOG_E("non support");
        return ERR_NOSUP;
    }
    device->oflags |= oflag;
    
    //执行驱动层的init函数
    if((device->ops->init) && (device->reference_count == 0)) {
        if(device->ops->init(device) != 0) {
            device->oflags = 0;
            return ERR_IO;
        }
    }
    
    //执行驱动层的open函数
    if(device->ops->open) {
        if(device->ops->open(device, oflag) != 0) {
            if(device->reference_count == 0) {
                device->oflags = 0;
            }
            return ERR_IO;
        }
    }
    
    //引用计数+1
    device->reference_count++;
    
    return ERR_NORMAL;
}

/*
 * 释放设备
 *
 * @param device 设备句柄
 *
 * @return 成功返回EOK
 */
static int __device_release(device_t *device)
{
    int32_t result = ERR_NORMAL;
    
    //引用计数-1
    device->reference_count--;
    
    //执行驱动层的release函数
    if((device->ops->release) && (device->reference_count == 0)) {
        result = device->ops->release(device);
    }
    
    if(result == ERR_NORMAL) {
        //成功复位oflags
        device->oflags = 0;
    }
    else {
        //释放失败
        device->reference_count++;
    }
    
    return result;
}

/**
 * 注册设备
 *
 * @param device 设备句柄
 * @param name 设备名
 * @param flags 设备支持的打开方式
 *
 * @return 成功返回EOK
 */
int32_t device_register(device_t *device, const char *name, uint32_t flags)
{
    if((!device) || (!device->ops) || (!name)){
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    //检查设备是否已经存在
    if(device_find(name)) {
        LOG_E("device duplication of name");
        return ERR_INVAL;
    }
    
    //创建互斥锁
    device->lock = xSemaphoreCreateRecursiveMutex();
    if(!device->lock) {
        LOG_E("create lock failed");
        return ERR_NOMEM;
    }
    
    //初始化设备参数
    device->flags = flags;
    device->oflags = 0;
    device->reference_count = 0;
    strncpy(device->name, name, MAX_NAME_LENGHT);
    device->timeout = portMAX_DELAY;
    
    //将设备插入链表
    taskENTER_CRITICAL();
    list_insert_after(&device_list, &device->node);
    taskEXIT_CRITICAL();
    
    return  ERR_NORMAL;
}

/**
 * 查找设备
 *
 * @param 设备名称
 *
 * @return 成功返回找到的设备，失败返回NULL
 */
device_t *device_find(const char *name)
{
    device_t *device;
    list_t *tmp;
    
    if(!name){
        LOG_E("parameter error");
        return NULL;
    }
    
    //遍历链表，查找设备
    taskENTER_CRITICAL();
    list_for_each(tmp, &device_list) {
        device = container_of(tmp, device_t, node);
        if(strncmp(device->name, name, MAX_NAME_LENGHT) == 0) {
            taskEXIT_CRITICAL();
            return device;
        }
    }
    taskEXIT_CRITICAL();
    
    return NULL;
}

/*
 * 校验设备幻术
 *
 * @param device 设备句柄
 * @param magic 设备幻术
 *
 * @return 成功返回EOK
 */
int32_t device_check(device_t *device, uint32_t magic)
{
    if(!device) {
        return ERR_INVAL;
    }
    return device->magic==magic ? ERR_NORMAL : ERR_INVAL;;
}

/*
 * 打开设备
 *
 * @param name 设备名称
 * @param oflag 打开方式
 *
 * @return 成功返回设备句柄，失败返回NULL
 */
device_t *device_open(const char *name, uint32_t oflag)
{
    device_t *device;

    if((!name) || (oflag == 0)){
        LOG_E("parameter error");
        return NULL;
    }
    
    //查找设备
    device = device_find(name);
    if(!device) {
        LOG_E("no device");
        return NULL;
    }
    
    //加锁
    if(xSemaphoreTakeRecursive(device->lock, portMAX_DELAY) != pdPASS) {
        LOG_E("lock failed");
        return NULL;
    }
    
    //获取设备
    if(__device_take(device, oflag) != ERR_NORMAL) {
        //解锁
        xSemaphoreGiveRecursive(device->lock);
        return NULL;
    }
    
    //解锁
    xSemaphoreGiveRecursive(device->lock);
    
    return device;
}

/*
 * 关闭设备
 *
 * @param device 设备句柄
 *
 * @return 成功返回EOK
 */
int32_t device_close(device_t *device)
{
    int32_t result;
    
    if(!device) {
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    //加锁
    if(xSemaphoreTakeRecursive(device->lock, portMAX_DELAY) != pdPASS) {
        LOG_E("lock failed");
        return ERR_ERROR;
    }
    
    //释放设备
    result = __device_release(device);
    
    //解锁
    xSemaphoreGiveRecursive(device->lock);
    
    return result;
}

/*
 * 读设备
 *
 * @param device 设备句柄
 * @param buffer 用户缓存
 * @param size 要读取的大小
 *
 * @return  成功返回读取的个数，失败返回错误码
 */
ssize_t device_read(device_t *device, void *buffer, size_t size)
{
    if((!device) || (!buffer) || (size == 0)) {
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    //检查打开方式
    if(!(device->oflags & DEVICE_RDONLY)) {
        LOG_E("non support");
        return ERR_NOSUP;
    }
    
    //调用驱动的pread函数
    if(device->ops->pread) {
        return device->ops->pread(device, buffer, size, 0);
    }
    
    LOG_E("non support");
    return ERR_NOSUP;
}

/*
 * 写设备
 *
 * @param device 设备句柄
 * @param buffer 用户缓存
 * @param size 要写取的大小
 *
 * @return 成功返回写入的个数，失败返回错误码
 */
ssize_t device_write(device_t *device, const void *buffer, size_t size)
{
    if((!device) || (!buffer) || (size == 0)) {
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    //检查打开方式
    if(!(device->oflags & DEVICE_WRONLY)) {
        LOG_E("non support");
        return ERR_NOSUP;
    }
    
    //调用驱动层的pwrite函数
    if(device->ops->pwrite) {
        return device->ops->pwrite(device, buffer, size, 0);
    }
    
    LOG_E("non support");
    return ERR_NOSUP;
}

/*
 * 读设备
 *
 * @param device 设备句柄
 * @param buffer 用户缓存
 * @param size 要读取的大小
 * @param pos 偏移
 *
 * @return 成功返回读取的个数，失败返回错误码
 */
ssize_t device_pread(device_t *device, void *buffer, size_t size, uint32_t pos)
{
    if((!device) || (!buffer) || (size == 0)) {
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    //检查打开方式
    if(!(device->oflags & DEVICE_RDONLY)) {
        LOG_E("non support");
        return ERR_NOSUP;
    }
    
    //调用驱动的pread函数
    if(device->ops->pread) {
        return device->ops->pread(device, buffer, size, pos);
    }
    
    LOG_E("non support");
    return ERR_NOSUP;
}

/*
 * 写设备
 *
 * @param device 设备句柄
 * @param buffer 用户缓存
 * @param size 要写入的大小
 * @param pos 偏移
 *
 * @return 成功返回写入的个数，失败返回错误码
 */
ssize_t device_pwrite(device_t *device, const void *buffer, size_t size, uint32_t pos)
{
    if((!device) || (!buffer) || (size == 0)) {
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    //检查打开方式
    if(!(device->oflags & DEVICE_WRONLY)) {
        LOG_E("non support");
        return ERR_NOSUP;
    }
    
    //调用驱动层的pwrite函数
    if(device->ops->pwrite) {
        return device->ops->pwrite(device, buffer, size, pos);
    }
    
    LOG_E("non support");
    return ERR_NOSUP;
}

/*
 * 控制设备
 *
 * @param device 设备句柄
 * @param command 控制命令
 * @param args 命令参数
 *
 * @return 成功返回EOK
 */
int32_t device_ctrl(device_t *device, uint32_t command, void *args)
{
    uint32_t *p_oflags = (uint32_t*)args;
    TickType_t *p_timeout = (TickType_t*)args;
    
    if(!device) {
        LOG_E("parameter error");
        return ERR_INVAL;
    }
    
    switch(command) {
    //获取打开方式
    case DEVICE_GET_OFLAG:
        if(!p_oflags) {
            LOG_E("parameter error");
            return ERR_INVAL;
        }
        *p_oflags = device->oflags;
        return ERR_NORMAL;
    //设置打开方式
    case DEVICE_SET_OFLAG:
        if(!p_oflags) {
            LOG_E("parameter error");
            return ERR_INVAL;
        }
        device->oflags = *p_oflags;
        return ERR_NORMAL;
    //获取接收超时时间
    case DEVICE_GET_TIMEOUT:
        if(!p_timeout) {
            LOG_E("parameter error");
            return ERR_INVAL;
        }
        *p_timeout = device->timeout;
         return ERR_NORMAL;
    //设置接收超时时间
    case DEVICE_SET_TIMEOUT:
        if(!p_timeout) {
            LOG_E("parameter error");
            return ERR_INVAL;
        }
        device->timeout = *p_timeout;
        return ERR_NORMAL;
    //执行驱动层的control函数
    default:
        if(device->ops->control) {
            return device->ops->control(device, command, args);
        }
        else {
            LOG_E("non support");
            return ERR_NOSUP;
        }
    }
}
